package lib.self.adapter.recycler;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;

import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import lib.self.AppEx;
import lib.self.LogMgr;
import lib.self.adapter.interfaces.ITreeAdapter;
import lib.self.adapter.interfaces.ITreeBean;
import lib.self.adapter.interfaces.OnAdapterClickListener;
import lib.self.adapter.interfaces.OnTreeRecyclerItemClickListener;
import lib.self.bean.TreeBean;
import lib.self.bean.TreeChildBean;
import lib.self.ex.interfaces.IFitParams;
import lib.self.ex.interfaces.IOption;
import lib.self.util.autoFit.FitDpUtil;
import lib.self.util.autoFit.FitViewParamsUtil;
import lib.self.util.view.ViewUtil;

/**
 * description: MultiRecyclerAdapter 用于二级列表---子item可以为多个
 * author: Steven Xiao
 * date: 2018/8/21
 */
//FIXME 功能未完成
public abstract class MultiTreeRecyclerAdapterEx<T extends TreeBean<C>, C extends TreeChildBean,
        VH extends RecyclerViewHolderEx> extends Adapter<VH> implements IFitParams, IOption, ITreeAdapter<T, C> {
    protected final String TAG = getClass().getSimpleName();
    private final int KTypeParent = 0x1000001;//父条目
    private List<T> mTs;
    private List<T> mRealTs;
    private LayoutInflater mInflater = null;
    private OnTreeRecyclerItemClickListener mItemClickListener;
    private boolean mHasHeader;
    private boolean mEnableLongClick;
    private HashMap<View, ViewClickListener> mMapClickLsn = null;
    private OnAdapterClickListener mOnAdapterClickListener;

    @Override
    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view = getLayoutInflater().inflate(getConvertViewResId(viewType), parent, false);
        autoFitAll(view);

        final VH vh = initViewHolder(view, viewType);

//        initView(vh.getLayoutPosition(), vh, viewType);

        view.setOnClickListener(v -> {
            if (mItemClickListener != null) {
                int layoutPosition = vh.getLayoutPosition();
                LogMgr.e(TAG, "position = " + layoutPosition);
                if (hasHeader()) {
                    layoutPosition--;
                }
                T item = getRealItem(layoutPosition);
                if (item.isParentItem()) {
                    mItemClickListener.onParentItemClick(view, layoutPosition, item.getParentPosition());
                } else {
                    mItemClickListener.onChildItemClick(view, layoutPosition, item.getParentPosition(), item.getChildPosition());
                }
            }
        });

        view.setOnLongClickListener(v -> {
            if (mEnableLongClick) {
                if (mItemClickListener != null) {
                    int layoutPosition = vh.getLayoutPosition();
                    if (hasHeader()) {
                        layoutPosition--;
                    }
                    T item = getRealItem(layoutPosition);
                    if (item.isParentItem()) {
                        mItemClickListener.onParentItemLongClick(view, layoutPosition, item.getParentPosition());
                    } else {
                        mItemClickListener.onChildItemLongClick(view, layoutPosition, item.getParentPosition(), item.getChildPosition());
                    }
                }
                return true;
            }
            return false;
        });

        return vh;
    }

    @Override
    public void onBindViewHolder(VH holder, int position) {
        T item = getRealItem(position);
        int parentPosition = item.getParentPosition();
        int childPosition = item.getChildPosition();
        if (item.isParentItem()) {
            refreshParentView(position, parentPosition, holder);
        } else {
            refreshChildView(position, parentPosition, childPosition, holder);
        }
    }

    @Override
    public int getItemCount() {
        return getCount();
    }

    /**
     * 设置点击监听
     *
     * @param listener
     */
    public final void setOnTreeRecyclerItemClickListener(OnTreeRecyclerItemClickListener listener) {
        mItemClickListener = listener;
    }

    @Override
    public int getItemViewType(int position) {
        T item = getRealItem(position);
        if (item.isParentItem()) {
            return KTypeParent;
        } else {
            return getItemViewChildType(item.getParentPosition(), item.getChildPosition());
        }
    }

    /**
     * 是否允许长点击
     *
     * @param enable
     */
    public final void setEnableLongClick(boolean enable) {
        this.mEnableLongClick = enable;
    }

    public LayoutInflater getLayoutInflater() {
        if (mInflater == null) {
            mInflater = LayoutInflater.from(getContext());
        }
        return mInflater;
    }

    public Context getContext() {
        return AppEx.getCt();
    }

//    protected void initView(int position, VH holder, int itemType) {
//    }

    protected abstract void refreshParentView(int realPosition, int parentPosition, VH holder);

    protected abstract void refreshChildView(int realPosition, int parentPosition, int childPosition, VH holder);

    protected int getConvertViewResId(int itemType) {
        if (itemType == KTypeParent) {
            return getConvertParentViewResId();
        } else {
            return getConvertChildViewResId(itemType);
        }
    }

    public abstract int getConvertParentViewResId();

    public abstract int getItemViewChildType(int parentPosition, int childPosition);

    public abstract int getConvertChildViewResId(int itemType);

    protected abstract VH initViewHolder(View view, int itemType);

    @Override
    public void setOnAdapterClickListener(OnAdapterClickListener listener) {
        mOnAdapterClickListener = listener;
    }

    @Override
    public void registerDataSetObserver(Object observer) {
        registerAdapterDataObserver((AdapterDataObserver) observer);
    }

    @Override
    public void unRegisterDataSetObserver(Object observer) {
        unregisterAdapterDataObserver((AdapterDataObserver) observer);
    }

    @Override
    public boolean isEmpty() {
        return getCount() == 0;
    }

    @Override
    public T getItem(int position) {
        if (mTs == null) {
            return null;
        }
        T t = null;
        try {
            t = mTs.get(position);
        } catch (Exception e) {
            LogMgr.e(TAG, e.toString());
        }
        return t;
    }

    @Override
    public C getChildItem(int parentPosition, int childPosition) {
        if (mTs == null) {
            return null;
        }
        T t;
        try {
            t = mTs.get(parentPosition);
            return t.getChildren().get(childPosition);
        } catch (Exception e) {
            LogMgr.e(TAG, e.toString());
        }
        return null;
    }

    public C getChildItem(int realPosition) {
        if (mRealTs == null) {
            return null;
        }
        return (C) mRealTs.get(realPosition);
    }

    @Override
    public T getRealItem(int position) {
        if (mTs == null) {
            return null;
        }
        T t = null;
        try {
            t = mRealTs.get(position);
        } catch (Exception e) {
            LogMgr.e(TAG, e.toString());
        }
        return t;
    }

    @Override
    public T getParentItem(int position) {
        if (mTs == null) {
            return null;
        }
        T realItem = getRealItem(position);
        T t = getItem(realItem.getParentPosition());
        return t;
    }

    @Override
    public int getLastItemPosition() {
        return 0;
    }

    @Override
    public int getCount() {
        return mTs == null ? 0 : mRealTs.size();
    }

    @Override
    public List<T> getData() {
        return mTs;
    }

    @Override
    public void setData(List<T> data) {
        mTs = data;
        if (mRealTs == null) {
            mRealTs = new ArrayList<>();
        } else {
            mRealTs.clear();
        }
        setRealData();
    }

    @Override
    public void removeAll() {
        if (mTs != null) {
            mTs.clear();
        }
        mRealTs.clear();
    }

    @Override
    public void remove(int position) {
        T t = getItem(position);
        removeRealItem(t);

        if (mTs != null) {
            remove(t);
        }
    }

    @Override
    public void remove(T item) {
        if (mTs != null) {
            mTs.remove(item);
        }
        removeRealItem(item);
    }

    private void removeRealItem(T item) {
        mRealTs.remove(item);
        List children = item.getChildren();
        if (children != null && !children.isEmpty()) {
            for (int i = 0; i < item.getChildren().size(); i++) {
                mRealTs.remove(item.getChildren().get(i));
            }
        }
        updateRealData();
    }

    private void updateRealData() {
        for (int i = 0; i < getData().size(); i++) {
            T t = getData().get(i);
            t.setParentPosition(i);
            List children = t.getChildren();
            if (children != null && !children.isEmpty()) {
                updateChildren(i, children);
            }
        }
    }

    @Override
    public void addAll(int position, List<T> items) {
        if (mTs != null && items != null) {
            mTs.addAll(position, items);
        }

        T t = getItem(position);
        List children = t.getChildren();
        int realStartIndex;
        if (children != null && !children.isEmpty()) {
            Object o = children.get(children.size() - 1);
            realStartIndex = mRealTs.indexOf(o);
        } else {
            realStartIndex = mRealTs.indexOf(t);
        }

        List<T> tempList = new ArrayList<>();
        for (int i = 0; i < items.size(); i++) {
            T tempT = items.get(i);
            tempList.add(tempT);
            List<C> tempChildren = tempT.getChildren();
            if (tempChildren != null && !tempChildren.isEmpty()) {
                for (int j = 0; j < tempChildren.size(); j++) {
                    ITreeBean bean = tempChildren.get(j);
                    bean.setChildPosition(j);
                    tempList.add((T) bean);
                }
            }
        }
        mRealTs.addAll(realStartIndex, tempList);
        updateRealData();
    }

    @Override
    public void addAll(List<T> data) {
        int startPosition = getData().size();
        if (data == null) {
            return;
        }
        if (mTs == null) {
            mTs = data;
        } else {
            mTs.addAll(data);
        }

        addRealData(data, startPosition);
    }

    @Override
    public void addRealData(List<T> data, int startPosition) {
        for (int i = 0; i < data.size(); i++) {
            T t = data.get(i);
            addRealItem(t, startPosition + i);
        }
    }

    @Override
    public void add(T item) {
        int startPosition = getData().size();
        if (item == null) {
            return;
        }

        if (mTs == null) {
            mTs = new ArrayList<>();
        }
        mTs.add(item);

        addRealItem(item, startPosition);
    }

    public void addRealItem(T t, int startPosition) {
        t.setParentPosition(startPosition);
        mRealTs.add(t);
        List<C> children = t.getChildren();
        addChildren(startPosition, children);
    }

    @Override
    public void add(int position, T item) {
        if (item == null) {
            return;
        }
        if (mTs == null) {
            mTs = new ArrayList<>();
        }
        mTs.add(position, item);

        int realStartIndex;
        if (position != 0) {
            T t = getItem(position - 1);
            List children = t.getChildren();
            if (children != null && !children.isEmpty()) {
                Object o = children.get(children.size() - 1);
                realStartIndex = mRealTs.indexOf(o);
            } else {
                realStartIndex = mRealTs.indexOf(t);
            }
        } else {
            realStartIndex = 0;
        }

        List<T> tempList = new ArrayList<>();
        tempList.add(item);
        List<C> tempChildren = item.getChildren();
        if (tempChildren != null && !tempChildren.isEmpty()) {
            for (int j = 0; j < tempChildren.size(); j++) {
                ITreeBean bean = tempChildren.get(j);
                bean.setChildPosition(j);
                tempList.add((T) bean);
            }
        }
        mRealTs.addAll(realStartIndex, tempList);
        updateRealData();

        LogMgr.e(TAG, "parent position = " + item.getParentPosition());
    }


    /**
     * 子条目直接添加到指定位置
     */
    public void addChildItem(int parentPosition, int childPosition, C childItem) {
        T parentItem = getItem(parentPosition);
        int parentItemPosition = mRealTs.indexOf(parentItem);

        childItem.setParentPosition(parentPosition);
        parentItem.getChildren().add(childPosition, childItem);
        mRealTs.add(parentItemPosition + childPosition + 1, (T) childItem);

        List children = mTs.get(parentPosition).getChildren();
        updateChildren(parentPosition, children);
    }

    /**
     * 获取item所在的真正位置
     */
    public int getItemPosition(T t) {
        if (mRealTs.contains(t)) {
            return mRealTs.indexOf(t);
        }
        return 0;
    }

    /**
     * 子条目直接加到最后一条
     */
    public void addChildItem(int parentPosition, C childItem) {
        T parentItem = getItem(parentPosition);
        int parentItemPosition = mRealTs.indexOf(parentItem);

        parentItem.getChildren().add(childItem);
        childItem.setParentPosition(parentPosition);
        childItem.setChildPosition(parentItem.getChildren().size());
        mRealTs.add(parentItemPosition + parentItem.getChildren().size(), (T) childItem);
    }


    public void removeChildItem(int realPosition) {
        T childItem = mRealTs.get(realPosition);
        int parentPosition = childItem.getParentPosition();
        int childPosition = childItem.getChildPosition();
        List children = mTs.get(parentPosition).getChildren();
        children.remove(childPosition);
        updateChildren(parentPosition, children);
        mRealTs.remove(realPosition);
    }

    @Override
    public void setRealData() {
        for (int i = 0; i < mTs.size(); i++) {
            T t = mTs.get(i);
            t.setParentPosition(i);
            mRealTs.add(t);
            List<C> children = t.getChildren();
            addChildren(i, children);
        }
    }

    private void addChildren(int parentPosition, List<C> children) {
        if (children != null && !children.isEmpty()) {
            for (int j = 0; j < children.size(); j++) {
                ITreeBean bean = children.get(j);
                bean.setParentPosition(parentPosition);
                bean.setChildPosition(j);
                mRealTs.add((T) bean);
            }
        }
    }

    private void updateChildren(int parentPosition, List<ITreeBean> children) {
        if (children != null && !children.isEmpty()) {
            for (int j = 0; j < children.size(); j++) {
                ITreeBean bean = children.get(j);
                bean.setParentPosition(parentPosition);
                bean.setChildPosition(j);
            }
        }
    }

    /**
     * FIXME 临时解决方案 有头部时位置-1
     */
    public boolean hasHeader() {
        return mHasHeader;
    }

    public void setHasHeader(boolean hasHeader) {
        this.mHasHeader = hasHeader;
    }

    @Override
    public List<T> getRealData() {
        return mRealTs;
    }

    @Override
    public void autoFitAll(View view) {
        FitViewParamsUtil.autoFitAll(view);
    }

    @Override
    public int dpToPx(float dp) {
        return FitDpUtil.dpToPx(dp, getContext());
    }

    /**
     * 监听控件的点击, 可以不重写, 交给外部处理
     *
     * @param position
     * @param view
     * @see #setOnAdapterClickListener(OnAdapterClickListener)
     */
    protected void onViewClick(int position, View view) {
    }

    /**
     * 根据view的id和item的position设置对应的lsn, 使用和convertView一样的缓存模式
     *
     * @param position
     * @param view
     */
    public void setOnViewClickListener(int position, View view) {
        if (view == null) {
            return;
        }

        if (mMapClickLsn == null) {
            mMapClickLsn = new HashMap<>();
        }

        ViewClickListener listener = mMapClickLsn.get(view);
        if (listener == null) {
            //表示这个view没有被设置过listener
            listener = new ViewClickListener(position);
            view.setOnClickListener(listener);
            mMapClickLsn.put(view, listener);
        } else {
            listener.mPosition = position;
        }
    }

    /**
     * 去掉点击监听, 主要是为了不响应press效果
     *
     * @param view
     */
    protected void removeOnViewClickListener(View view) {
        if (mMapClickLsn == null) {
            return;
        }

        mMapClickLsn.remove(view);
        view.setOnClickListener(null);
        view.setClickable(false);
    }

    @Override
    public void showView(View view) {
        ViewUtil.showView(view);
    }

    @Override
    public void hideView(View view) {
        ViewUtil.hideView(view);
    }

    @Override
    public void goneView(View view) {
        ViewUtil.goneView(view);
    }

    @Override
    public void startActivity(Class<? extends Activity> cls) {
        Intent intent = new Intent(getContext(), cls);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        getContext().startActivity(intent);
    }

    @Override
    public void startActivityForResult(Class<? extends Activity> cls, int requestCode) {

    }

    private class ViewClickListener implements OnClickListener {
        private int mPosition;

        public ViewClickListener(int position) {
            this.mPosition = position;
        }

        @Override
        public void onClick(View v) {
            onViewClick(mPosition, v);

            if (mOnAdapterClickListener != null) {
                mOnAdapterClickListener.onAdapterClick(mPosition, v);
            }
        }
    }
}
